/*
 * Copyright 2005-2013 rsico. All rights reserved.
 * Support: http://www.rsico.cn
 * License: http://www.rsico.cn/license
 */
package com.rzico.core.plugin.ahrcu;

import com.alibaba.fastjson.JSONObject;
import com.rzico.core.entity.SysPlugin;
import com.rzico.core.entity.SysUser;
import com.rzico.core.plugin.PaymentPlugin;
import com.rzico.exception.CustomException;
import com.rzico.util.MD5Utils;
import com.rzico.util.RedisHandler;
import com.rzico.util.StringUtils;
import com.rzico.util.XMLUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Plugin - 安庆农商行小程序支付(微信、支付宝)
 * @author rsico Team
 * @version 3.0
 */
@Component("miniPayPlugin")
@Slf4j
public class MiniPayPlugin extends PaymentPlugin {

	public static final String UNIFIED_ORDER_URL = "https://wxtest2.ahrcu.com:3443/cposp/pay/miniProgramPay";
	public static final String REFUNDS_ORDER_URL = "https://wxtest2.ahrcu.com:3443/cposp/pay/refund";

	public static final String QUERY_ORDER_URL = "https://wxtest2.ahrcu.com:3443/cposp/pay/nativeOrderQuery";
	public static final String REFUND_QUERY_ORDER_URL = "https://wxtest2.ahrcu.com:3443/cposp/pay/refundQuery";
	public static final String SIGN_IN_URL = "https://wxtest2.ahrcu.com:3443/cposp/pay/signIn";

	SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

	@Value("${weixin.appid}")
	private String wx_appid;
	@Value("${weixin.mchid}")
	private String wx_mchid;
	@Value("${weixin.mchSecret}")
	private String wx_mch_secret;
	@Value("${setting.host}")
	private String host;

	@Autowired
	private RedisHandler redisHandler;

	@Override
	public String getName() {
		return "小程序支付";
	}

	@Override
	public String getVersion() {
		return "1.0";
	}

	/**
	 * 作用：生成签名
	 */
	public String getSign(HashMap<String, Object> params, SysPlugin sysPlugin) throws Exception {
		String str = joinKeyValue(params,"&",true,"sign","key");
		// 签名步骤二：在string后加入KEY
		if ("1".equals(sysPlugin.getAttribute("method"))) {
			str += "&key=" + sysPlugin.getAttribute("key");
		} else {
			str += "&key=" + wx_mch_secret;
		}
		// 签名步骤三：MD5加密 签名步骤四：所有字符转为大写
		str = MD5Utils.getMD5Str(str).toUpperCase();
		return str;
	}

	/**
	 * 获取用户号
	 * @param sysUser SysUser
	 * @return 获取用户号
	 */
	@Override
	public String getUserId(SysUser sysUser) {
		return sysUser.getWxmId();
	}

	@Override
	public Map<String, Object> trade(SysPlugin sysPlugin,String tradeNo, String description, BigDecimal totalfee, String userId, HttpServletRequest request) {

		HashMap<String, Object> packageParams = new HashMap<>();
		HashMap<String, Object> finalpackage = new HashMap<>();
		String createNoncestr = StringUtils.CreateNoncestr();
		String terminalNo = sysPlugin.getAttribute("terminalNo");


		if ("1".equals(sysPlugin.getAttribute("method"))) {
			//小程序ID
			packageParams.put("appid", sysPlugin.getAttribute("appid"));
			packageParams.put("merchantNo", sysPlugin.getAttribute("mchid"));
		} else {
			packageParams.put("appid", wx_appid);
			packageParams.put("merchantNo", wx_mchid);
		}
		packageParams.put("terminalNo", terminalNo);
		packageParams.put("batchNo", getSignIn(sysPlugin));
		packageParams.put("traceNo", getTraceNo(terminalNo));
		packageParams.put("outTradeNo", tradeNo);
		packageParams.put("openId", userId);
		packageParams.put("tradeChannel", "01");
		packageParams.put("nonce_str", createNoncestr);
		description = description.trim().replaceAll("[^\u4E00-\u9FA5]", "");
		if (description.length()>40) {
			String bodyStr = description.substring(0, 40);
			packageParams.put("remark",bodyStr);
		} else {
			packageParams.put("remark", description);
		}
		packageParams.put("out_trade_no", tradeNo);

		// 这里写的金额为1 分到时修改
		packageParams.put("transAmount", totalfee.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).toString());
		packageParams.put("notify_url", getNotifyUrl(sysPlugin));

		try {
			String sign = getSign(packageParams,sysPlugin);
			packageParams.put("sign", sign);
		} catch (Exception e) {
			e.printStackTrace();
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg", "设置异常1");
			return finalpackage;
		}

		try {
			String data = JSONObject.toJSONString(packageParams);
			String respStr = post(UNIFIED_ORDER_URL,data,null);
			log.info(respStr);

			Map resultMap = XMLUtils.xmlToMap(respStr);
			String return_code = (String) resultMap.get("resultCode");
			if (return_code.equals("00")) {

				String packages = "prepay_id=" + (String) resultMap.get("payInfo");
				finalpackage.put("appId", sysPlugin.getAttribute("appid"));
				finalpackage.put("package", packages);
				finalpackage.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
				finalpackage.put("nonceStr", StringUtils.CreateNoncestr());
				finalpackage.put("signType", "MD5");

				String finalsign = getSign(finalpackage, sysPlugin);
				finalpackage.put("paySign", finalsign);

				finalpackage.put("resultMessage", resultMap.get("resultMessage"));
				finalpackage.put("merchantNo", resultMap.get("merchantNo"));
				finalpackage.put("batchNo", resultMap.get("batchNo"));
				finalpackage.put("terminalNo", resultMap.get("terminalNo"));
				finalpackage.put("traceNo", resultMap.get("traceNo"));
				finalpackage.put("transTime", resultMap.get("transTime"));
				finalpackage.put("cposOrderId", resultMap.get("cposOrderId"));
				finalpackage.put("itpOrderId", resultMap.get("itpOrderId"));
				finalpackage.put("return_code", "0000");
			} else {
				finalpackage.put("return_code", "0003");
				finalpackage.put("error_msg", (String) resultMap.get("resultMessage"));

			}

		} catch (Exception e) {
			log.info(e.getMessage());
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg", "设置异常2");
		}
		log.info("收款:"+finalpackage);
		return finalpackage;

	}

	@Override
	public Map<String, Object> verifyNotify(SysPlugin sysPlugin,HttpServletRequest request) {
		HashMap<String, Object> finalpackage = new HashMap<>();
		try {
			HashMap<String, Object> resultMap = new HashMap<String, Object>();
			StringBuffer info = new StringBuffer();
			InputStream in = request.getInputStream();
			BufferedInputStream buf = new BufferedInputStream(in);
			byte[] buffer = new byte[1024];
			int iRead;
			while ((iRead = buf.read(buffer)) != -1) {
				info.append(new String(buffer, 0, iRead, "UTF-8"));
			}
			resultMap = XMLUtils.xmlToMap(info.toString());
			log.info("异常通知:"+info.toString());
			if (resultMap.get("result_code").toString().equals("SUCCESS")) {
				String sign = getSign(resultMap,sysPlugin);
				if (sign.equals(resultMap.get("sign").toString())) {
					finalpackage.put("return_code", "0000");
					finalpackage.put("tradeNo", (String) resultMap.get("out_trade_no"));
					finalpackage.put("tranSn", (String) resultMap.get("transaction_id"));
					return finalpackage;
				}
			}
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg",(String) resultMap.get("return_msg"));
		} catch (Exception e) {
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg", e.getMessage());
		}
		return finalpackage;
	}

	/**
	 * 查询订单的支付结果  0000成功  9999处理中  其他的失败
	 */
	@Override
    public Map<String, Object> tradeQuery(SysPlugin sysPlugin,String tradeNo,String tranSn,HttpServletRequest request) {

		HashMap<String, Object> finalpackage = new HashMap<>();
		String createNoncestr = StringUtils.CreateNoncestr();
		String terminalNo = sysPlugin.getAttribute("terminalNo");
		HashMap<String, Object> parameterMap = new HashMap<String, Object>();
		if ("1".equals(sysPlugin.getAttribute("method"))) {
			parameterMap.put("appid", sysPlugin.getAttribute("appid"));
			parameterMap.put("merchantNo", sysPlugin.getAttribute("mchid"));
		} else {
			parameterMap.put("appid", wx_appid);
			parameterMap.put("merchantNo", wx_mchid);
		}
		parameterMap.put("terminalNo", terminalNo);
		parameterMap.put("batchNo", getSignIn(sysPlugin));
		parameterMap.put("traceNo", getTraceNo(terminalNo));
		parameterMap.put("outTradeNo",tradeNo);
		parameterMap.put("nonce_str", createNoncestr);
		try {
			parameterMap.put("sign",getSign(parameterMap,sysPlugin));
		} catch (Exception e) {
			finalpackage.put("return_code", "0003");
			finalpackage.put("error_msg","签名出错");
			return finalpackage;
		}

		try {
			String data = JSONObject.toJSONString(parameterMap);
			String resultXml = post(QUERY_ORDER_URL, data,null);
			Map<String,Object> resultMap = XMLUtils.xmlToMap(resultXml);
			String return_code = (String) resultMap.get("resultCode");
			if (return_code.equals("00")) {
				String status = (String) resultMap.get("orderStatus");
				if (status.equals("3")) {
					//信e付订单号
					finalpackage.put("tranSn", resultMap.get("itpOrderId"));
					finalpackage.put("cposOrderId", resultMap.get("cposOrderId"));
					finalpackage.put("itpOrderId", resultMap.get("itpOrderId"));
					finalpackage.put("chnOrderId", resultMap.get("chnOrderId"));
					finalpackage.put("tradeChannel", resultMap.get("tradeChannel"));
					finalpackage.put("return_code", "0000");
					finalpackage.put("error_msg","支付成功");
				} else if (status.equals("6")) {
					finalpackage.put("return_code", "0002");
					finalpackage.put("error_msg","交易成功有退款");
				} else if (status.equals("2")) {
					finalpackage.put("return_code", "0001");
					finalpackage.put("error_msg","正在付款");
				} else if (status.equals("4")) {
					finalpackage.put("return_code", "0003");
					finalpackage.put("error_msg","交易失败");
				} else if (status.equals("1")) {
					finalpackage.put("return_code", "0003");
					finalpackage.put("error_msg","订单未支付");
				} else if (status.equals("5")) {
					finalpackage.put("return_code", "0003");
					finalpackage.put("error_msg","交易关闭");
				} else if (status.equals("8")) {
					finalpackage.put("return_code", "0003");
					finalpackage.put("error_msg","二维码未使用");
				} else {
					finalpackage.put("return_code", "0003");
					finalpackage.put("error_msg", "未知状态");
				}

			} else{
				finalpackage.put("return_code", "9999");
				finalpackage.put("error_msg", (String) resultMap.get("resultMessage"));
			}
		} catch (Exception e) {
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg", "设置异常");
		}

		return finalpackage;
	}

	@Override
	public String getNotifyMessage(HttpServletRequest request) {
		return "SUCCESS";
	}

	/**
	 * 申请退款
	 */
	@Override
	public Map<String, Object> refund(SysPlugin sysPlugin, String refundNo, String tradeNo, BigDecimal totalfee, BigDecimal refundfee , HttpServletRequest request) {
		HashMap<String, Object> finalpackage = new HashMap<String, Object>();
		HashMap<String, Object> paramsMap = new HashMap<String, Object>();
		String terminalNo = sysPlugin.getAttribute("terminalNo");

		DecimalFormat decimalFormat = new DecimalFormat("#");
		if ("1".equals(sysPlugin.getAttribute("method"))) {
			paramsMap.put("merchantNo", sysPlugin.getAttribute("mchid"));
		} else {
			paramsMap.put("merchantNo", wx_mchid);
		}
		paramsMap.put("terminalNo", "");
		paramsMap.put("batchNo", getSignIn(sysPlugin));
		paramsMap.put("traceNo", getTraceNo(terminalNo));
		//业务订单
		paramsMap.put("outTradeNo", tradeNo);
		//退款单号
		paramsMap.put("mchtRefundNo",refundNo);
		//退款金额
		paramsMap.put("refundAmount", decimalFormat.format(refundfee.multiply(new BigDecimal(100))));

		try {
			paramsMap.put("sign",getSign(paramsMap,sysPlugin));
		} catch (Exception e) {
			finalpackage.put("return_code", "0003");
			finalpackage.put("error_msg","签名出错");
			return finalpackage;
		}

		try {
			String data = JSONObject.toJSONString(paramsMap);
//			HttpClient httpClient =	createSSLHttpClient(sysPlugin);
			String resultXml = post(REFUNDS_ORDER_URL,data,null);
			HashMap<String,Object> resultMap = XMLUtils.xmlToMap(resultXml);

			if("00".equals(resultMap.get("resultCode").toString()) ){
				if ("01".equals(resultMap.get("refundStatus").toString())){
					finalpackage.put("return_code", "0000");
					finalpackage.put("error_msg", "退款成功");
					finalpackage.put("merchantNo", resultMap.get("merchantNo"));
					finalpackage.put("terminalNo", resultMap.get("terminalNo"));
					finalpackage.put("traceNo", resultMap.get("traceNo"));
					finalpackage.put("batchNo", resultMap.get("batchNo"));
					finalpackage.put("refundStatus", resultMap.get("refundStatus"));
					//原交易的总金额
					finalpackage.put("transAmount", resultMap.get("transAmount"));
					//本次退款金额
					finalpackage.put("refundAmount", resultMap.get("refundAmount"));
					//云收单退款单号
					finalpackage.put("cposRefundOrderId", resultMap.get("cposRefundOrderId"));
					finalpackage.put("itpOrderId", resultMap.get("itpOrderId"));
					finalpackage.put("chnOrderId", resultMap.get("chnOrderId"));
					finalpackage.put("tradeChannel", resultMap.get("tradeChannel"));
				}else if ("00".equals(resultMap.get("refundStatus").toString())){
					finalpackage.put("return_code", "0001");
					finalpackage.put("error_msg", "退款中");
				}else if ("02".equals(resultMap.get("refundStatus").toString())){
					finalpackage.put("return_code", "0003");
					finalpackage.put("error_msg", "退款失败");
				}
				return finalpackage;
			}else{
				finalpackage.put("return_code", "0003");
				finalpackage.put("error_msg", resultMap.get("errorDesc").toString());
				return finalpackage;
			}
		} catch (Exception e) {
			log.error(e.getMessage());
			finalpackage.put("return_code", "0003");
			finalpackage.put("error_msg","提交银行出错");
			return finalpackage;
		}


	}

	/**
	 * 查询退款
	 */
	@Override
	public Map<String, Object> refundQuery(SysPlugin sysPlugin, String refundNo,String tranSn, HttpServletRequest request) {
		HashMap<String, Object> finalpackage = new HashMap<>();
		String createNoncestr = StringUtils.CreateNoncestr();
		String terminalNo = sysPlugin.getAttribute("terminalNo");

		HashMap<String, Object> parameterMap = new HashMap<String, Object>();
		if ("1".equals(sysPlugin.getAttribute("method"))) {
			parameterMap.put("merchantNo", sysPlugin.getAttribute("mchid"));
		} else {
			parameterMap.put("merchantNo", wx_mchid);
		}
		parameterMap.put("terminalNo", sysPlugin.getAttribute("terminalNo"));
		parameterMap.put("batchNo", getSignIn(sysPlugin));
		parameterMap.put("traceNo", getTraceNo(terminalNo));
		parameterMap.put("itpOrderId",tranSn);

		parameterMap.put("mchtRefundNo",refundNo);
		parameterMap.put("nonce_str", createNoncestr);
		try {
			parameterMap.put("sign",getSign(parameterMap,sysPlugin));
		} catch (Exception e) {
			finalpackage.put("return_code", "0003");
			finalpackage.put("error_msg","签名出错");
			return finalpackage;
		}

		try {
			String data = JSONObject.toJSONString(parameterMap);
			String resultXml = post(REFUND_QUERY_ORDER_URL, data,null);
//			Map<String,Object> resultMap = XMLUtils.xmlToMap(resultXml);
			JSONObject resultMap = JSONObject.parseObject(resultXml);
			String return_code = resultMap.getString("resultCode");
			if (return_code.equals("00")) {
				finalpackage.put("tranSn", resultMap.get("itpOrderId"));
				finalpackage.put("cposOrderId", resultMap.get("cposOrderId"));
				finalpackage.put("itpOrderId", resultMap.get("itpOrderId"));
				finalpackage.put("chnOrderId", resultMap.get("chnOrderId"));
				finalpackage.put("tradeChannel", resultMap.get("tradeChannel"));
				finalpackage.put("refundDetailList", resultMap.get("refundDetailList"));
				finalpackage.put("return_code", "0000");
				finalpackage.put("error_msg","成功");
			} else{
				finalpackage.put("return_code", "9999");
				finalpackage.put("error_msg", (String) resultMap.get("resultMessage"));
			}
		} catch (Exception e) {
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg", "设置异常");
		}
		return finalpackage;
	}

	public String getSignIn(SysPlugin sysPlugin){
		String key = sysPlugin.getAttribute("terminalNo") +":" + sdf.format(new Date());
		Object batchNo = redisHandler.get(key);
		if (null == batchNo){
			Map<String, Object>  map = signIn(sysPlugin);
			String returnCode = (String) map.get("return_code");
			if ("0000".equals(returnCode)){
				batchNo = map.get("batchNo");
			}else{
				throw new CustomException("签到失败");
			}
		}
		return String.valueOf(batchNo);
	}

	public String getTraceNo(String terminalNo){
		String traceKey = terminalNo + ":traceNo";
		Object traceNo = redisHandler.get(traceKey);
		if (null == traceNo){
			redisHandler.set(traceKey, 1);
			traceNo = StringUtils.createCode(String.valueOf(2));
		}else {
			if (999999 == (long)traceNo){
				redisHandler.set(traceKey, 1);
			}else {
				redisHandler.set(traceKey, (long)traceNo + 1);
			}
			traceNo = StringUtils.createCode(String.valueOf(traceNo));
		}
		return String.valueOf(traceNo);
	}


	public Map<String, Object> signIn(SysPlugin sysPlugin){
		HashMap<String, Object> finalpackage = new HashMap<>();
		HashMap<String, Object> parameterMap = new HashMap<String, Object>();
		if ("1".equals(sysPlugin.getAttribute("method"))) {
			parameterMap.put("merchantNo", sysPlugin.getAttribute("mchid"));
		} else {
			parameterMap.put("merchantNo", wx_mchid);
		}
		parameterMap.put("terminalNo", sysPlugin.getAttribute("terminalNo"));

		try {
			String data = JSONObject.toJSONString(parameterMap);
			String resultXml = post(SIGN_IN_URL, data,null);
			Map<String,Object> resultMap = XMLUtils.xmlToMap(resultXml);
			String return_code = (String) resultMap.get("resultCode");
			if (return_code.equals("00")) {
				String key = sysPlugin.getAttribute("terminalNo") +":"+ sdf.format(new Date());
				redisHandler.set(key, resultMap.get("batchNo"), 86400L);
				finalpackage.put("batchNo", resultMap.get("batchNo"));
				finalpackage.put("sessionID", resultMap.get("sessionID"));
				finalpackage.put("doubMchntFlag", resultMap.get("doubMchntFlag"));
				finalpackage.put("singAmtLimit", resultMap.get("singAmtLimit"));
				finalpackage.put("keyLength", resultMap.get("keyLength"));
				finalpackage.put("algType", resultMap.get("algType"));
				finalpackage.put("macKey", resultMap.get("macKey"));
				finalpackage.put("macKeycheckValue", resultMap.get("macKeycheckValue"));
				finalpackage.put("pik", resultMap.get("pik"));
				finalpackage.put("pikCheckValue", resultMap.get("pikCheckValue"));
				finalpackage.put("tdk", resultMap.get("tdk"));
				finalpackage.put("tdkCheckValue", resultMap.get("tdkCheckValue"));
				finalpackage.put("return_code", "0000");
				finalpackage.put("error_msg","成功");
			} else{
				finalpackage.put("return_code", "9999");
				finalpackage.put("error_msg", (String) resultMap.get("resultMessage"));
			}
		} catch (Exception e) {
			finalpackage.put("return_code", "9999");
			finalpackage.put("error_msg", "签到异常");
		}
		return finalpackage;


	}
}